home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / util / moni / Scout-src.lha / source / objects / scout_tasks.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-02-13  |  33.8 KB  |  959 lines

  1. /**
  2.  * Scout - The Amiga System Monitor
  3.  *
  4.  *------------------------------------------------------------------
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * You must not use this source code to gain profit of any kind!
  21.  *
  22.  *------------------------------------------------------------------
  23.  *
  24.  * @author Andreas Gelhausen
  25.  * @author Richard Körber <rkoerber@gmx.de>
  26.  */
  27.  
  28.  
  29.  
  30. #include "system_headers.h"
  31.  
  32. int  taskcnt;
  33. APTR taskmoretext0,taskmoretext1a,taskmoretext1b,taskmoretext2,taskmoretext3;
  34. APTR procmorelist;
  35. APTR processmoretext0,processmoretext1a,processmoretext1b,processmoretext2,processmoretext3;
  36. APTR processmoretext4,processmoretext5,processmoretext6a,processmoretext6b,processmoretext7;
  37.  
  38. static APTR TaskPool = NULL;
  39.  
  40. BOOL timer_ticking = FALSE;
  41.  
  42. struct SignalSemaphore *patchsem = NULL;
  43. static UBYTE __aligned SemaphoreName[] = "« Scout's CPU patch »";
  44.  
  45. VOID __asm (*cleartaskdata) (VOID) = NULL;
  46. LONG  __asm (*gettaskdata) (register __d0 struct Task *) = NULL;
  47. struct Task * __asm (*getaddedtask) (VOID) = NULL;
  48. char  *switchstate = NULL;
  49.  
  50. LONG totalmicros,cpuseconds = 1,cpumicros = 0;
  51.  
  52. #define CHEATSTACKSIZE  1024
  53. #define CHEATTASKNAME   "« Scout's cheat task »"
  54. struct Task *cheattask = NULL;
  55.  
  56. static void cheattask_func (void) {
  57.    while (TRUE) {}
  58. }
  59.  
  60. struct Task * AddCheatTask (void) {
  61.    struct Task *result;
  62.  
  63.    if (result = AllocVec(CHEATSTACKSIZE + sizeof (struct Task), MEMF_ANY|MEMF_CLEAR)) {
  64.       result->tc_SPLower = sizeof (struct Task) + (char *) result;
  65.       result->tc_SPUpper = CHEATSTACKSIZE + sizeof (struct Task) + (char *) result;
  66.       result->tc_SPReg = result->tc_SPUpper;
  67.  
  68.       result->tc_Node.ln_Name = CHEATTASKNAME;
  69.       result->tc_Node.ln_Pri = -128;
  70.       result->tc_Node.ln_Type = NT_TASK;
  71.  
  72.       AddTask(result, (APTR) &cheattask_func, NULL);
  73.    }
  74.    return (result);
  75. }
  76.  
  77. void RemoveCheatTask (void) {
  78.    RemTask(cheattask);
  79.    FreeVec(cheattask);
  80.    cheattask = NULL;
  81. }
  82.  
  83. struct Task * TaskExists (struct Task *tasktofind) {
  84.    struct   Task  *task, *result = NULL;
  85.  
  86.    if ((tasktofind == (struct Task *) 42) || (tasktofind == myprocess))
  87.       return (myprocess);
  88.  
  89.    Forbid();
  90.  
  91.    task = FIRSTTASKREADY;
  92.    while (task->tc_Node.ln_Succ != 0) {
  93.       if (task == tasktofind)
  94.          result = task;
  95.       task = (struct Task *) task->tc_Node.ln_Succ;
  96.    }
  97.  
  98.    task = FIRSTTASKWAIT;
  99.    while (task->tc_Node.ln_Succ != 0) {
  100.       if (task == tasktofind)
  101.          result = task;
  102.       task = (struct Task *) task->tc_Node.ln_Succ;
  103.    }
  104.  
  105.    Permit();
  106.    return (result);
  107. }
  108.  
  109. void HandleTimerRequest (BOOL waitstate) {
  110.    struct Window *taskwin;
  111.  
  112.    if (!waitstate && timer_ticking) {
  113.       AbortIO((struct IORequest *) TimerIORequest);
  114.       WaitIO((struct IORequest *) TimerIORequest);
  115.       timer_ticking = FALSE;
  116.    }
  117.  
  118.    if ((patchsem) && (*switchstate)) {
  119.  
  120.       // if (((waitstate) && (TimerIORequest->tr_node.io_Message.mn_Node.ln_Type != NT_MESSAGE)) || (! waitstate)) {
  121.       if ((waitstate && timer_ticking) || !waitstate) {
  122.  
  123.          (*cleartaskdata) ();
  124.  
  125.          if (WI_Tasks) {
  126.             TimerIORequest->tr_time.tv_secs = cpuseconds;
  127.             TimerIORequest->tr_time.tv_micro = cpumicros;
  128.             TimerIORequest->tr_node.io_Command = TR_ADDREQUEST;
  129.             SendIO ((struct IORequest *) TimerIORequest);
  130.             timer_ticking = TRUE;
  131.  
  132.             get (WI_Tasks, MUIA_Window_Window, &taskwin);
  133.             if (taskwin) UpdateTasks();
  134.          }
  135.       }
  136.    }
  137. }
  138.  
  139. void CheckCPUUsage (void)
  140. {
  141.    ULONG semsize, size;
  142.  
  143.    get (CY_CpuUsage,MUIA_Cycle_Active,&updatetimestate);
  144.  
  145.    if (updatetimestate) {
  146.       semsize = (sizeof(struct SignalSemaphore) + strlen(SemaphoreName) + 7) & ~7;
  147.  
  148.       Forbid();
  149.       if (patchsem = FindSemaphore ((UBYTE *) &SemaphoreName)) {
  150.          CodeAddress = semsize + 8 + (char *) patchsem;
  151.          Permit();
  152.       } else {
  153.          AsmTimerBase = (struct Library *) FindName (&SysBase->DeviceList, TIMERNAME);
  154.          Permit();
  155.  
  156.          if (AsmTimerBase) {
  157.             size = (ULONG) ((char *) &CodeAddress - (char *) &MySwitch + 8);
  158.             if (patchsem = AllocVec(semsize + 8 + size, MEMF_ANY|MEMF_CLEAR)) {
  159.                Forbid();
  160.                FreeVec(patchsem);
  161.                patchsem = AllocVec(semsize + 8 + size, MEMF_ANY|MEMF_CLEAR|MEMF_REVERSE);
  162.                Permit();
  163.  
  164.                if (patchsem) {
  165.                   strcpy((char *)patchsem + sizeof(struct SignalSemaphore), SemaphoreName);
  166.  
  167.                   CodeAddress = semsize + 8 + (char *) patchsem;
  168.                   OldSwitch = *((ULONG *) (-52 + (char *) SysBase));
  169.                   OldAdd = *((ULONG *) (-280 + (char *) SysBase));
  170.  
  171.                   CopyMem(&MySwitch, (APTR) CodeAddress, size);
  172.  
  173.                   InitSemaphore(patchsem);
  174.                   patchsem->ss_Link.ln_Name = (char *)patchsem + sizeof(struct SignalSemaphore); // (char *) &SemaphoreName - (char *) &MySwitch + CodeAddress;
  175.                   AddSemaphore(patchsem);
  176.  
  177. //                  cleartaskdata = (VOID (* __asm) (VOID)) ((char *) &ClearTaskData - (char *) &MySwitch + CodeAddress);
  178. //                  gettaskdata = (LONG (* __asm)(register __d0 struct Task *)) ((char *) &GetTaskData - (char *) &MySwitch + CodeAddress);
  179. //                  getaddedtask = (struct Task *(* __asm)(VOID)) ((char *) &GetAddedTask - (char *) &MySwitch + CodeAddress);
  180.  
  181.                   SetPatches();
  182.                   ShowTasks();
  183.                }
  184.             }
  185.          } else {
  186.             aprintf ("Couldn't find %s!\n", TIMERNAME);
  187.          }
  188.       }
  189.    }
  190.  
  191.    if (patchsem) {
  192.       cleartaskdata = (VOID (* __asm) (VOID)) ((char *) &ClearTaskData - (char *) &MySwitch + CodeAddress);
  193.       gettaskdata = (LONG (* __asm)(register __d0 struct Task *)) ((char *) &GetTaskData - (char *) &MySwitch + CodeAddress);
  194.       getaddedtask = (struct Task *(* __asm)(VOID)) ((char *) &GetAddedTask - (char *) &MySwitch + CodeAddress);
  195.       switchstate = (char *) &SwitchState - (char *) &MySwitch + CodeAddress;
  196.  
  197.       *switchstate = (char) updatetimestate;
  198.       HandleTimerRequest (FALSE);
  199.  
  200.       if (updatetimestate == 2) {
  201.          if (!cheattask) cheattask = AddCheatTask();
  202.       } else {
  203.          if (cheattask) RemoveCheatTask();
  204.          set(cpucount,MUIA_Gauge_Current,0);
  205.          set(cpucount,MUIA_Gauge_InfoText,"\0330-----");
  206.       }
  207.    }
  208. }
  209.  
  210. char * GetTaskState (UBYTE state) {
  211.    char *TaskStateText[] = {
  212.       "frozen","added","run","ready","wait","except","removed",
  213.       "invalid","< ??? >"
  214.    };
  215.  
  216.    UBYTE TaskState[] = {
  217.       TS_FROZEN,TS_ADDED,TS_RUN,TS_READY,TS_WAIT,TS_EXCEPT,TS_REMOVED,
  218.       TS_INVALID
  219.    };
  220.  
  221.    int i = 0;
  222.  
  223.    while (TaskState[i]) {
  224.       if (state == TaskState[i]) {
  225.          return (TaskStateText[i]);
  226.       }
  227.       i++;
  228.    }
  229.    if (TaskState[i] == TS_INVALID) {
  230.       return (TaskStateText[i]);
  231.    } else {
  232.       return (TaskStateText[i+1]);
  233.    }
  234. }
  235.  
  236. char * GetNodeType (UBYTE type) {
  237.    char *NodeTypeText[] = {
  238.       "task","interrupt","device","msgport",
  239.       "message","freemsg","replymsg","resource","library",
  240.       "memory","softint","font","process","semaphore",
  241.       "signalsem","bootnode","kickmem","graphics",
  242.       "deathmessage","user","extended",
  243.       "unknown","< ??? >"
  244.    };
  245.  
  246.    UBYTE NodeType[] = {
  247.       NT_TASK,NT_INTERRUPT,NT_DEVICE,NT_MSGPORT,
  248.       NT_MESSAGE,NT_FREEMSG,NT_REPLYMSG,NT_RESOURCE,
  249.       NT_LIBRARY,NT_MEMORY,NT_SOFTINT,NT_FONT,NT_PROCESS,
  250.       NT_SEMAPHORE,NT_SIGNALSEM,NT_BOOTNODE,NT_KICKMEM,
  251.       NT_GRAPHICS,NT_DEATHMESSAGE,NT_USER,NT_EXTENDED,
  252.       NT_UNKNOWN
  253.    };
  254.  
  255.    int i = 0;
  256.  
  257.    while (NodeType[i]) {
  258.       if (type == NodeType[i]) {
  259.          return (NodeTypeText[i]);
  260.       }
  261.       i++;
  262.    }
  263.    if (NodeType[i] == NT_UNKNOWN)
  264.       return (NodeTypeText[i]);
  265.    else
  266.       return (NodeTypeText[i+1]);
  267. }
  268.  
  269. __asm __saveds LONG tasklist_cmpcpufunc (register __a1 struct TaskEntry *te1, register __a2 struct TaskEntry *te2)
  270. {
  271.     LONG result;
  272.  
  273.     result = strcmpi(te2->ts_cpu, te1->ts_cpu);
  274.     if (result == 0) result = strcmpi(te1->ts_name, te2->ts_name);
  275.  
  276.     return result;
  277. }
  278.  
  279. struct Hook tasklist_cmpcpuhook = {
  280.  {NULL, NULL},
  281.  (ULONG (* )())tasklist_cmpcpufunc,
  282.  NULL, NULL
  283. };
  284.  
  285. __asm __saveds LONG tasklist_cmpprifunc (register __a1 struct TaskEntry *te1, register __a2 struct TaskEntry *te2)
  286. {
  287.    long  eins = 0, zwei = 0;
  288.  
  289.    IsDec (te1->ts_pri, &eins);
  290.    IsDec (te2->ts_pri, &zwei);
  291.    return zwei - eins;
  292. }
  293.  
  294. struct Hook tasklist_cmpprihook = {
  295.  {NULL, NULL},
  296.  (ULONG (* )())tasklist_cmpprifunc,
  297.  NULL, NULL
  298. };
  299.  
  300. __asm __saveds LONG tasklist_cmpaddressfunc (register __a1 struct ListEntry *le1, register __a2 struct ListEntry *le2)
  301. {
  302.    return (LONG)le1->le_adr - (LONG)le2->le_adr;
  303. }
  304.  
  305. struct Hook tasklist_cmpaddresshook = {
  306.  {NULL, NULL},
  307.  (ULONG (* )())tasklist_cmpaddressfunc,
  308.  NULL, NULL
  309. };
  310.  
  311. __asm __saveds LONG tasklist_dspfunc(register __a2 char **array, register __a1 struct TaskEntry *taskentry, register __a0 struct Hook *hook)
  312. {
  313.    if (taskentry) {
  314.       *array++ = taskentry->ts_address;
  315.       *array++ = taskentry->ts_type;
  316.       *array++ = taskentry->ts_pri;
  317.       *array++ = taskentry->ts_num;
  318.       *array++ = taskentry->ts_state;
  319.       *array++ = taskentry->ts_sigwait;
  320.       *array++ = taskentry->ts_cpu;
  321.       *array++ = taskentry->ts_name;
  322.       *array   = NULL;
  323.    } else {
  324.       *array++ = ESC "bAddress";
  325.       *array++ = ESC "bln_Type";
  326.       *array++ = ESC "bln_Pri";
  327.       *array++ = ESC "bNUM";
  328.       *array++ = ESC "bState";
  329.       *array++ = ESC "bSigWait";
  330.       *array++ = ESC "bCPU %";
  331.       *array++ = ESC "bln_Name";
  332.       *array   = NULL;
  333.    }
  334.    return (0);
  335. }
  336.  
  337. struct Hook tasklist_dsphook = {
  338.  {NULL, NULL},
  339.  (ULONG (* )())tasklist_dspfunc,
  340.  NULL, NULL
  341. };
  342.  
  343. void FreeTasks (void)
  344. {
  345.     MyFreePoolStructs(&TaskPool, tasktext, NULL, tasklist);
  346. }
  347.  
  348. char * GetTaskName (struct Task *task) {
  349.    struct CommandLineInterface   *cli;
  350.    int   lauf = 0;
  351. //   int   offset = 0;
  352.    char  *pointer;
  353.    char  *error = "<notask>";
  354.  
  355.    if (task) {
  356.       if ((task->tc_Node.ln_Type == NT_PROCESS) && (((struct Process *) task)->pr_CLI != 0)) {
  357.          cli = (struct CommandLineInterface *) (((struct Process *) task)->pr_CLI << 2);
  358.          if ((pointer = (char *) cli->cli_CommandName) &&
  359.              (pointer = (char *) (((LONG) pointer) << 2) + 1) &&
  360.              (pointer[0])) {
  361.  
  362.             while (pointer[lauf]) {
  363.                if (pointer[lauf++] != ' ')
  364.                   return (pointer);
  365.             }
  366. /*
  367.             pointer = (char *) (((LONG) pointer) << 2);
  368.  
  369.             while (*(pointer + lauf) != '\0') {
  370.                if ((*(pointer + lauf) == '/') || ((*(pointer + lauf) == ':') && (*(pointer + lauf + 1) != '\0'))) {
  371.                   offset = lauf;
  372.                }
  373.                lauf++;
  374.             }
  375.             if (lauf)
  376.                return (pointer + 1 + offset);
  377. */
  378.          }
  379.       }
  380.       if (((task->tc_Node.ln_Type == NT_PROCESS) || (task->tc_Node.ln_Type == NT_TASK)) \
  381.           && (task->tc_Node.ln_Succ)) {
  382.          return (task->tc_Node.ln_Name);
  383.       } else {
  384.          return (error);
  385.       }
  386.    }
  387.    return (NULL);
  388. }
  389.  
  390. void GetTaskNumber (struct Task *task, char string[]) {
  391.    if ((task->tc_Node.ln_Type == NT_TASK) || (((struct Process *)task)->pr_TaskNum == 0)){
  392.       strcpy (string, "---");
  393.    } else {
  394.       _sprintf (string, "%ld", ((struct Process *) task)->pr_TaskNum);
  395.    }
  396. }
  397.  
  398. void GetTaskEntry (struct Task *task, struct TaskEntry *taskentry, BOOL cpuflag) {
  399.    char  tasknum[4];
  400.    ULONG  cpu,zehntel;
  401.  
  402.    if (! taskentry->ts_ptr) {
  403.       taskentry->ts_ptr = task;
  404.  
  405.       _sprintf (taskentry->ts_address, "$%08lx", task);
  406.       strcpy (taskentry->ts_type, GetNodeType (task->tc_Node.ln_Type));
  407.       GetTaskNumber (task, tasknum);
  408.       strncpy (taskentry->ts_num, tasknum, 3);
  409.    }
  410.  
  411.    _sprintf (taskentry->ts_pri, "%4ld ", task->tc_Node.ln_Pri);
  412.    strcpy (taskentry->ts_state, GetTaskState ((UBYTE) task->tc_State));
  413.    _sprintf (taskentry->ts_sigwait, "$%08lx", task->tc_SigWait);
  414.    strncpy (taskentry->ts_name, nonetest (GetTaskName (task)), NODENAMELENGTH);
  415.    healstring (taskentry->ts_name);
  416.  
  417.    if ((cpuflag) && (totalmicros = *((ULONG *) ((char *) &TotalMicros1 + 4 - (char *) &MySwitch + CodeAddress)))) {
  418.       cpu = (*gettaskdata)(task);
  419.  
  420.       if (!(zehntel = UDivMod32 (totalmicros, 1000)))
  421.          zehntel = 1;
  422.  
  423.       zehntel = UDivMod32 (cpu, zehntel);
  424.       cpu = UDivMod32 (zehntel, 10);
  425.       zehntel -= UMult32 (cpu, 10);
  426.                 if (cpu > 99) {
  427.                         cpu = 100;
  428.                         zehntel = 0;
  429.                 }
  430.       _sprintf (taskentry->ts_cpu, "%3ld.%ld ", cpu, zehntel);
  431.    } else {
  432.       strcpy (taskentry->ts_cpu, "  0.0 ");
  433.    }
  434. }
  435.  
  436. void UpdateTasks (void) {
  437.    struct   TaskEntry   *taskentry,*cmptaskentry;
  438.    struct   Task        *task;
  439.    int      i;
  440.    ULONG    cheatcpu;
  441.    BOOL     changed;
  442.  
  443.    while (task = (*getaddedtask) ()) {
  444.       if (TaskExists (task) && (taskentry = tbAllocPooled(TaskPool, sizeof(struct TaskEntry)))) {
  445.          GetTaskEntry (task, taskentry, TRUE);
  446.          InsertSortedEntry (tasklist, (APTR *) &taskentry);
  447.          SetCountText (taskcount, ++taskcnt);
  448.       }
  449.    }
  450.  
  451.    if (cmptaskentry = AllocVec(sizeof(struct TaskEntry), MEMF_ANY|MEMF_CLEAR)) {
  452.       changed = FALSE;
  453.       for (i=0;;i++) {
  454.          DoMethod (tasklist,MUIM_List_GetEntry,i,&taskentry);
  455.  
  456.          if (taskentry) {
  457.             if (task = TaskExists ((struct Task *) taskentry->ts_ptr)) {
  458.                CopyMem (taskentry, cmptaskentry, sizeof (struct TaskEntry));
  459.                GetTaskEntry (task, taskentry, TRUE);
  460.                if (memcmp (taskentry,cmptaskentry, sizeof (struct TaskEntry))) {
  461.                   if (tasklist_cmphook_ptr != TaskSortList[3]) DoMethod (tasklist,MUIM_List_Redraw,i);
  462.                   changed = TRUE;
  463.                }
  464.             } else {
  465.                if (! (task = TaskExists ((struct Task *) taskentry->ts_ptr))) {
  466.                   DoMethod (tasklist, MUIM_List_Remove, i--);
  467.                   SetCountText (taskcount, --taskcnt);
  468.                }
  469.             }
  470.          } else {
  471.             break;
  472.          }
  473.       }
  474.       if (changed && tasklist_cmphook_ptr == TaskSortList[3]) DoMethod(tasklist, MUIM_List_Sort);
  475.       FreeVec(cmptaskentry);
  476.    }
  477.  
  478.    if (updatetimestate == 2) {
  479.       cheatcpu = (*gettaskdata)(cheattask);
  480.       if (totalmicros) {
  481.          set(cpucount,MUIA_Gauge_InfoText,"%ld%%");
  482.          set(cpucount,MUIA_Gauge_Current,UDivMod32 (UMult32 (totalmicros - cheatcpu, 100), totalmicros));
  483. //*         MySetContents (cpucount, ESC "r%ld \%", UDivMod32 (UMult32 (totalmicros - cheatcpu, 100), totalmicros));
  484.       }
  485.    }
  486. }
  487.  
  488. int GetTasks (struct TaskEntry **first) {
  489.    #define maxtasknumber 512
  490.  
  491.    struct   Task        *task;
  492.    struct   TaskEntry   *taskentry,*previous = NULL;
  493.    unsigned long        *buffer,maxcnt,loopcnt;
  494.  
  495.    int taskcnt = 0;
  496.    *first = 0;
  497.  
  498.    if (!TaskPool) TaskPool = tbCreatePool(MEMF_CLEAR, 4096, 4096);
  499.  
  500.    if (clientstate) {
  501.       if (SendDaemon ("GetTaskList")) {
  502.          while ((taskentry = tbAllocPooled(TaskPool, sizeof(struct TaskEntry))) \
  503.            && (ReceiveDecodedEntry ((UBYTE *) taskentry, sizeof (struct TaskEntry)))) {
  504.             IsHex (taskentry->ts_address, (long *) &taskentry->ts_ptr);
  505.  
  506.             if (! *first)
  507.                *first = taskentry;
  508.             if (previous)
  509.                previous->ts_next = taskentry;
  510.  
  511.             taskcnt++;
  512.             previous = taskentry;
  513.          }
  514.       }
  515.    } else {
  516.       loopcnt = 0;
  517.       maxcnt = maxtasknumber;
  518.    
  519.       if (buffer = AllocVec((maxtasknumber+1) * sizeof(unsigned long), MEMF_ANY|MEMF_CLEAR)) {
  520.          Forbid();
  521.    
  522.          task = FIRSTTASKREADY;
  523.          while ((task->tc_Node.ln_Succ != 0) && (maxcnt)) {
  524.             buffer[taskcnt++] = (ULONG) task;
  525.             maxcnt--;
  526.             task = (struct Task *)task->tc_Node.ln_Succ;
  527.          }
  528.    
  529.          task = FIRSTTASKWAIT;
  530.          while ((task->tc_Node.ln_Succ != 0) && (maxcnt)) {
  531.             buffer[taskcnt++] = (ULONG) task;
  532.             maxcnt--;
  533.             task = (struct Task *)task->tc_Node.ln_Succ;
  534.          }
  535.    
  536.          Permit();
  537.  
  538.          while ((buffer[loopcnt]) && (taskentry = tbAllocPooled(TaskPool, sizeof(struct TaskEntry)))) {
  539.             if (! *first)
  540.                *first = taskentry;
  541.             if (previous)
  542.                previous->ts_next = taskentry;
  543.    
  544.             GetTaskEntry ((struct Task *) buffer[loopcnt++], taskentry, FALSE);
  545.             previous = taskentry;
  546.          }
  547.          FreeVec(buffer);
  548.    
  549.          if (taskentry = tbAllocPooled(TaskPool, sizeof(struct TaskEntry))) {
  550.             if (previous)
  551.                previous->ts_next = taskentry;
  552.    
  553.             GetTaskEntry (myprocess, taskentry, FALSE);
  554.             taskentry->ts_ptr = (struct Task *) 42;  // 42, damit Scouts Prozess oben in der Liste steht!
  555.             taskcnt++;
  556.             // previous = taskentry;
  557.          }
  558.       }
  559.    }
  560.    return (taskcnt);
  561. }
  562.  
  563. void PrintTasks (char *filename) {
  564.    int   i=1;
  565.    BPTR  handle;
  566.    struct TaskEntry *entryp = NULL;
  567.  
  568.    handle = HandlePrintStart (filename);
  569.    if ((handle) && (PrintOneLine (handle, "\n  Address  Type     Pri NUM State    SigWait  Name\n\n"))) {
  570.       if (! WI_Tasks) {
  571.          i = GetTasks (&entryp);
  572.       }
  573.       if (i) {
  574.          for (i=0;;i++) {
  575.             if (WI_Tasks)
  576.                DoMethod (tasklist,MUIM_List_GetEntry,i,&entryp);
  577.             if (!entryp) break;
  578.  
  579.             _sprintf (tmpstr2, " %s %-7.7s %4s%3s %-7.7s %s %s\n", entryp->ts_address, entryp->ts_type, entryp->ts_pri, entryp->ts_num, entryp->ts_state, entryp->ts_sigwait, entryp->ts_name);
  580.             if (! (PrintOneLine (handle, tmpstr2)))
  581.                break;
  582.  
  583.             if (! WI_Tasks)
  584.                entryp = entryp->ts_next;
  585.          }
  586.       }
  587.    }
  588.    HandlePrintStop();
  589. }
  590.  
  591. void ShowTasks (void) {
  592.    #define maxtasknumber 512
  593.  
  594.    struct   TaskEntry   *task;
  595.  
  596.    ApplicationSleep();
  597.    set(tasklist,MUIA_List_Quiet,TRUE);
  598.    set(tasklist,MUIA_List_CompareHook,tasklist_cmphook_ptr);
  599.    set(BT_TaskRemove, MUIA_Disabled, TRUE);
  600.    set(BT_TaskFreeze, MUIA_Disabled, TRUE);
  601.    set(BT_TaskActivate, MUIA_Disabled, TRUE);
  602.    set(BT_TaskPriority, MUIA_Disabled, TRUE);
  603.    set(BT_TaskSignal, MUIA_Disabled, TRUE);
  604.    set(BT_TaskBreak, MUIA_Disabled, TRUE);
  605.    set(BT_TaskMore, MUIA_Disabled, TRUE);
  606.  
  607.    if (clientstate) {
  608.       set(CY_CpuUsage, MUIA_Disabled, TRUE);
  609.    }
  610.    FreeTasks();
  611.  
  612.    taskcnt = GetTasks (&task);
  613.  
  614.    while (task) {
  615.       InsertSortedEntry (tasklist, (APTR *) &task);
  616.       task = task->ts_next;
  617.    }
  618.  
  619.    SetCountText (taskcount, taskcnt);
  620.    AwakeApplication();
  621.    set(tasklist,MUIA_List_Quiet,FALSE);
  622. }
  623.  
  624. void SendTaskList (void) {
  625.    struct   TaskEntry   *task;
  626.  
  627.    FreeTasks();
  628.    GetTasks (&task);
  629.  
  630.    while (task) {
  631.       SendEncodedEntry ((UBYTE *) task, sizeof (struct TaskEntry));
  632.       task = task->ts_next;
  633.    }
  634.    FreeTasks();
  635. }
  636.  
  637. void GetTaskMore (struct Task *task) {
  638.    unsigned char     *title = "TASK: ";
  639.    struct   WinFree  *ptr;
  640.  
  641.    if (ptr = AllocWinFree()) {
  642.       ptr->wf_Window = (APTR) WindowObject,
  643.  
  644. //      MUIA_Window_SizeGadget, FALSE,
  645.       MUIA_HelpNode, TasksText,
  646.       MUIA_Window_ID, MakeDetailID('.','T','A','S'),
  647.       WindowContents, HGroup,
  648.          Child, VGroup, MUIA_Group_SameWidth, TRUE,
  649.             Child, MyLabel2 ("Name:"),
  650.             Child, MyLabel2 ("Address:\nIDNestCnt:\nTrapAlloc:\nTrapAble:\nTrapData:\nTrapCode:\nUserData:"),
  651.             Child, MyLabel2 ("Flags:"),
  652.          End,
  653.          Child, VGroup, MUIA_Group_SameWidth, TRUE,
  654.             Child, taskmoretext0 = MyTextObject(),
  655.             Child, HGroup,
  656.                Child, VGroup,
  657.                   Child, taskmoretext1a = MyTextObject2(),
  658.                   Child, taskmoretext1b = KeyButtonF ('b', task->tc_Flags),
  659.                End,
  660.                Child, MyLabel ("State:\nTDNestCnt:\nExceptData:\nExceptCode:\nStackSize:\nSPLower:\nSPUpper:\nSPReg:"),
  661.                Child, taskmoretext2 = MyTextObject2(),
  662.                Child, MyLabel ("Pri:\nSigAlloc:\nSigWait:\nSigRecvd:\nSigExcept:\nSwitch():\nLaunch():\nMemEntry:"),
  663.                Child, taskmoretext3 = MyTextObject2(),
  664.             End,
  665.          End,
  666.       End, End;
  667.  
  668.       if (ptr->wf_Window) {
  669.          MySetContents (taskmoretext1a, ESC "r $%08lx\n%ld\n$%04lx\n$%04lx\n $%08lx\n $%08lx\n $%08lx", task, task->tc_IDNestCnt, task->tc_TrapAlloc, task->tc_TrapAble, task->tc_TrapData, task->tc_TrapCode, task->tc_UserData);
  670.          MySetContents (taskmoretext2, ESC "c%s\n" ESC "r%ld\n$%08lx\n$%08lx\n%ld\n$%08lx\n$%08lx\n$%08lx", GetTaskState ((BYTE) task->tc_State), task->tc_TDNestCnt, task->tc_ExceptData, task->tc_ExceptCode, (char *) task->tc_SPUpper - (char *) task->tc_SPLower, task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
  671.          MySetContents (taskmoretext3, ESC "r%ld\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", task->tc_Node.ln_Pri, task->tc_SigAlloc, task->tc_SigWait, task->tc_SigRecvd, task->tc_SigExcept, task->tc_Switch, task->tc_Launch, task->tc_MemEntry);
  672.  
  673.          HandleFlagsButtonPressed (taskmoretext1b, ptr, "(TASK)", "tc_Flags", task->tc_Flags, (struct LongFlag *) &tc_flags, NULL, 'b');
  674.          HandleWindowOpen (ptr, title, GetTaskName (task));
  675.          MySetContents (taskmoretext0, "%s", GetTaskName (task));
  676.          HandleWindowClose (ptr);
  677.       }
  678.    }
  679. }
  680.  
  681. __asm __saveds LONG procmore_dspfunc(register __a2 char **array, register __a1 struct HunkEntry *hunkentry, register __a0 struct Hook *hook)
  682. {
  683.    if (hunkentry) {
  684.       *array++ = hunkentry->he_lower;
  685.       *array++ = hunkentry->he_upper;
  686.       *array++ = hunkentry->he_size;
  687.       *array   = NULL;
  688.    } else {
  689.       *array++ = ESC "bLower";
  690.       *array++ = ESC "bUpper";
  691.       *array++ = ESC "bSize";
  692.       *array   = NULL;
  693.    }
  694.    return (0);
  695. }
  696.  
  697. struct Hook procmore_dsphook = {
  698.  {NULL, NULL},
  699.  (ULONG (* )())procmore_dspfunc,
  700.  NULL, NULL
  701. };
  702.  
  703. void GetSegList (struct Process *proc) {
  704.    struct HunkEntry  *hunkentry;
  705.    long  *seg;
  706.    long  size;
  707.  
  708.    set(procmorelist,MUIA_List_Quiet,TRUE);
  709.  
  710.    if (((seg = (long *) (((long) *((long *) (((long) proc->pr_SegList<<2) + 12)))<<2)) && points2ram((APTR) seg)) || \
  711.       ((proc->pr_CLI) && (seg = (long *) (((struct CommandLineInterface *) (proc->pr_CLI<<2))->cli_Module<<2)))) {
  712.  
  713.       while ((seg) && (hunkentry = tbAllocPooled(TaskPool, sizeof(struct HunkEntry)))) {
  714.          _sprintf (hunkentry->he_lower, "$%08lx", ((char *) seg) + 4);
  715.          size = *(seg - 1);
  716.          _sprintf (hunkentry->he_size, "%ld", size);
  717.          _sprintf (hunkentry->he_upper, "$%08lx", ((char *) seg) - 4 + size);
  718.  
  719.          InsertBottomEntry (procmorelist, (APTR *) &hunkentry);
  720.          seg = (long *) ((*seg)<<2);
  721.       }
  722.    }
  723.  
  724.    set(procmorelist,MUIA_List_Quiet,FALSE);
  725. }
  726.  
  727. void GetProcessMore (struct Process *proc) {
  728.    unsigned char     *title = "PROCESS: ";
  729.    unsigned char     tasknum[4];
  730.    struct   WinFree  *ptr;
  731.  
  732.    if (ptr = AllocWinFree()) {
  733.       ptr->wf_Window = (APTR) WindowObject,
  734.  
  735. //      MUIA_Window_SizeGadget, FALSE,
  736.       MUIA_HelpNode, TasksText,
  737.       MUIA_Window_ID, MakeDetailID('.','T','A','S'),
  738.       WindowContents, HGroup,
  739.          Child, VGroup, MUIA_Group_SameWidth, TRUE,
  740. #ifndef WINDOW_PROBLEMS
  741.             Child, MyLabel2 ("Name:"),
  742. #endif
  743.             Child, MyLabel2 ("Address:\nIDNestCnt:\nTrapAlloc:\nTrapAble:\nTrapData:\nTrapCode:\nUserData:"),
  744.             Child, MyLabel2 ("Flags:"),
  745.             Child, MyLabel2 ("Pad:\nGlobVec:\nResult2:\nCOS:\nCLI:\nWindowPtr:"),
  746.             Child, MyLabel2 ("\nHunks:\n\n\n\n"),
  747.             Child, MyVSpace(0),
  748.          End,
  749.          Child, VGroup, MUIA_Group_SameWidth, TRUE,
  750. #ifndef WINDOW_PROBLEMS
  751.             Child, processmoretext0 = MyTextObject(),
  752. #endif
  753.             Child, HGroup,
  754.                Child, VGroup,
  755.                   Child, HGroup,
  756.                      Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
  757.                         Child, processmoretext1a = MyTextObject(),
  758.                         Child, processmoretext1b = KeyButtonF ('b', ((struct Task *) proc)->tc_Flags),
  759.                         Child, processmoretext4 = MyTextObject(),
  760.                      End,
  761. //                     Child, MyHSpace(0),
  762.                      Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 60,
  763.                         Child, MyLabel ("State:\nTDNestCnt:\nExceptData:\nExceptCode:\nStackSize:\nSPLower:\nSPUpper:\nSPReg:"),
  764.                         Child, MyVSpace(0),
  765.                         Child, MyLabel ("SegList:\nTaskNum:\nCurrentDir:\nConsoleTask:\nReturnAddr:\nHomeDir:"),
  766.                      End,
  767.                      Child, VGroup, MUIA_Group_SameWidth, TRUE,
  768.                         Child, processmoretext2 = MyTextObject2(),
  769.                         Child, MyVSpace(0),
  770.                         Child, processmoretext5 = MyTextObject2(),
  771.                      End,
  772.                   End,
  773.                   Child, MyVSpace(2),
  774.                   Child, procmorelist = ListviewObject,
  775.                      MUIA_Listview_DoubleClick, TRUE,
  776.                      MUIA_Listview_Input, FALSE,
  777.                      MUIA_Listview_List, ListObject,
  778.                      MUIA_List_Format, "COL=0 DELTA=8,COL=1 DELTA=8,COL=2 P=\33r",
  779.                      MUIA_List_Title, TRUE,
  780.                      MUIA_List_DisplayHook, &procmore_dsphook,
  781.                      ReadListFrame,
  782.                      End,
  783.                   MUIA_CycleChain, TRUE,
  784.                   End,
  785.                End,
  786. //               Child, MyHSpace(0),
  787.                Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 60,
  788.                   Child, MyLabel ("Pri:\nSigAlloc:\nSigWait:\nSigRecvd:\nSigExcept:\nSwitch():\nLaunch():\nMemEntry:"),
  789.                   Child, MyLabel ("Flags:"),
  790.                   Child, MyLabel ("StackSize:\nStackBase:\nCIS:\nFileSystemTask:\nPktWait:"),
  791.                   Child, MyLabel ("ExitCode:\nExitData:\nArguments:\nLocalVars:\nShellPrivate:\nCES:"),
  792.                End,
  793.                Child, VGroup, MUIA_Group_SameWidth, TRUE,
  794.                   Child, processmoretext3 = MyTextObject2(),
  795.                   Child, processmoretext6b = KeyButtonF ('l', proc->pr_Flags),
  796.                   Child, processmoretext6a = MyTextObject2(),
  797.                   Child, processmoretext7 = MyTextObject2(),
  798.                End,
  799.             End,
  800.          End,
  801.       End, End;
  802.  
  803.       if (ptr->wf_Window) {
  804.          MySetContents (processmoretext1a, ESC "r$%08lx\n%ld\n$%04lx\n$%04lx\n$%08lx\n$%08lx\n$%08lx", proc, proc->pr_Task.tc_IDNestCnt, proc->pr_Task.tc_TrapAlloc, proc->pr_Task.tc_TrapAble, proc->pr_Task.tc_TrapData, proc->pr_Task.tc_TrapCode, proc->pr_Task.tc_UserData);
  805.          MySetContents (processmoretext2, ESC "c%s\n" ESC "r%ld\n$%08lx\n$%08lx\n%ld\n$%08lx\n$%08lx\n$%08lx", GetTaskState ((BYTE) proc->pr_Task.tc_State), proc->pr_Task.tc_TDNestCnt, proc->pr_Task.tc_ExceptData, proc->pr_Task.tc_ExceptCode, (char *) proc->pr_Task.tc_SPUpper - (char *) proc->pr_Task.tc_SPLower, proc->pr_Task.tc_SPLower, proc->pr_Task.tc_SPUpper, proc->pr_Task.tc_SPReg);
  806.          MySetContents (processmoretext3, ESC "r%ld\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", proc->pr_Task.tc_Node.ln_Pri, proc->pr_Task.tc_SigAlloc, proc->pr_Task.tc_SigWait, proc->pr_Task.tc_SigRecvd, proc->pr_Task.tc_SigExcept, proc->pr_Task.tc_Switch, proc->pr_Task.tc_Launch, proc->pr_Task.tc_MemEntry);
  807.          MySetContents (processmoretext4, ESC "r$%04lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", proc->pr_Pad, proc->pr_GlobVec, proc->pr_Result2, ((ULONG) proc->pr_COS)<<2, ((ULONG) proc->pr_CLI)<<2, proc->pr_WindowPtr);
  808.  
  809.          GetTaskNumber ((struct Task *) proc, tasknum);
  810.  
  811.          MySetContents (processmoretext5, ESC "r$%08lx\n%s\n$%08lx\n$%08lx\n$%08lx\n$%08lx", ((ULONG) proc->pr_SegList)<<2, tasknum, ((ULONG) proc->pr_CurrentDir)<<2, proc->pr_ConsoleTask, proc->pr_ReturnAddr, ((ULONG) proc->pr_HomeDir)<<2);
  812.          MySetContents (processmoretext6a, ESC "r%ld\n$%08lx\n$%08lx\n$%08lx\n$%08lx", proc->pr_StackSize, ((ULONG) proc->pr_StackBase)<<2, ((ULONG) proc->pr_CIS)<<2, proc->pr_FileSystemTask, proc->pr_PktWait);
  813.  
  814.          MySetContents (processmoretext7, ESC "r$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx\n$%08lx", proc->pr_ExitCode, proc->pr_ExitData, proc->pr_Arguments, proc->pr_LocalVars, proc->pr_ShellPrivate, ((ULONG) proc->pr_CES)<<2);
  815.  
  816.          GetSegList (proc);
  817.  
  818.          HandleFlagsButtonPressed (processmoretext1b, ptr, "(PROCESS)", "tc_Flags", ((struct Task *) proc)->tc_Flags, (struct LongFlag *) &tc_flags, NULL, 'b');
  819.          HandleFlagsButtonPressed (processmoretext6b, ptr, "(PROCESS)", "pr_Flags", proc->pr_Flags, (struct LongFlag *) &pr_flags, NULL, 'l');
  820.          HandleWindowOpen (ptr, title, GetTaskName ((struct Task *) proc));
  821.          set (ptr->wf_Window,MUIA_Window_ActiveObject,procmorelist);
  822. #ifndef WINDOW_PROBLEMS
  823.          MySetContents (processmoretext0, "%s", GetTaskName ((struct Task *) proc));
  824. #endif
  825.          HandleWindowClose (ptr);
  826.       }
  827.    }
  828. }
  829.  
  830.  
  831. APTR TaskSortList[] = {
  832.    &tasklist_cmpaddresshook,
  833.    &list_cmpnamehook,
  834.    &tasklist_cmpprihook,
  835.    &tasklist_cmpcpuhook,
  836.    NULL
  837. };
  838.  
  839. static const char *CYA_TaskSortText[] = {
  840.    "address",
  841.    "name",
  842.    "priority",
  843.    "CPU usage",
  844.    NULL
  845. };
  846.  
  847. static const char *CYA_CpuUsageText[] = {
  848.    "off",
  849.    "full",
  850.    " in % ",
  851.    NULL
  852. };
  853.  
  854. APTR WI_Tasks, tasklist, tasktext, tasktext2, taskcount, CY_TaskSort;
  855. int  tasksortstate = 0;
  856. APTR BT_TaskPrint, BT_TaskFreeze, BT_TaskActivate, cpucount, CY_CpuUsage;
  857. APTR BT_TaskUpdate, BT_TaskRemove, BT_TaskSignal, BT_TaskBreak, BT_TaskPriority, BT_TaskMore, BT_TaskExit;
  858.  
  859. char tasks_title[WINDOWTITLELEN];
  860.  
  861. void TasksWindow (BOOL state) {
  862.    if (state) {
  863.       if (WI_Tasks) {
  864.          ShowTasks();
  865.       } else {
  866.          WI_Tasks = WindowObject,
  867.          MUIA_Window_Title, MyGetWindowTitle (tasks_title, "TASKS"),
  868.          MUIA_HelpNode, TasksText,
  869.          MUIA_Window_ID, MakeListID('T','A','S','K'),
  870.          WindowContents, VGroup,
  871.             Child, tasklist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8 P=\33c,COL=2 DELTA=8 P=\33r,COL=3 DELTA=8 P=\33r,COL=4 DELTA=8 P=\33c,COL=5 DELTA=8,COL=6 DELTA=8 P=\33r,COL=7",&tasklist_dsphook),
  872.             Child, MyBelowSortedListview (&tasktext, &taskcount, &CY_TaskSort, CYA_TaskSortText, tasksortstate),
  873.             Child, MyVSpace(2),
  874.             Child, VGroup,
  875.                Child, HGroup, MUIA_Group_SameSize, TRUE,
  876.                   Child, BT_TaskPrint    = KeyButtonA (PrintText   ,ID_TASKPRINT),
  877.                   Child, BT_TaskFreeze   = KeyButtonA (FreezeText  ,ID_TASKFREEZE),
  878.                   Child, BT_TaskActivate = KeyButtonA (ActivateText,ID_TASKACTIVATE),
  879.                   Child, HGroup,
  880.                      Child, MyLabel2 (" CPU:"),
  881.                      Child, cpucount = GaugeObject,
  882.                        MUIA_Frame         , MUIV_Frame_Gauge,
  883.                        MUIA_Gauge_Horiz   , TRUE,
  884.                        MUIA_Gauge_Max     , 100,
  885.                        MUIA_Gauge_InfoText, "\0330-----",
  886.                        MUIA_Gauge_Current , 0,
  887.                      End,
  888.                   End,
  889.                   Child, CY_CpuUsage = CycleObject,
  890.                      MUIA_Weight, 0,
  891.                      MUIA_Cycle_Entries, CYA_CpuUsageText,
  892.                      MUIA_Cycle_Active, updatetimestate,
  893.                   End,
  894.                   Child, HGroup,
  895.                      Child, MyLabel2 (" Secs:"),
  896.                      Child, tasktext2 = StringObject,
  897.                         MUIA_String_BufferPos, 1,
  898.                         MUIA_String_MaxLen, 6, StringFrame,
  899.                         MUIA_String_EditHook, &realstring_edithook,
  900.                         MUIA_String_Contents, updatetimetext,
  901.                      End,
  902.                   End,
  903.                End,
  904.                Child, HGroup, MUIA_Group_SameSize, TRUE,
  905.                   Child, BT_TaskUpdate   = KeyButtonA (UpdateText  ,ID_TASKUPDATE),
  906.                   Child, BT_TaskRemove   = KeyButtonA (RemoveText  ,ID_TASKREMOVE),
  907.                   Child, BT_TaskSignal   = KeyButtonA (SignalText  ,ID_TASKSIGNAL),
  908.                   Child, BT_TaskBreak    = KeyButtonA (BreakText   ,ID_TASKBREAK),
  909.                   Child, BT_TaskPriority = KeyButtonA (PriorityText,ID_TASKPRIORITY),
  910.                   Child, BT_TaskMore     = KeyButtonA (MoreText    ,ID_TASKMORE),
  911.                   Child, BT_TaskExit     = KeyButtonA (ExitText    ,ID_TASKEXIT),
  912.                End,
  913.             End,
  914.          End, End;
  915.  
  916.          if (WI_Tasks) {
  917.             DoMethod (AP_Scout,OM_ADDMEMBER,WI_Tasks);
  918.             DoMethod (WI_Tasks,MUIM_Window_SetCycleChain,tasklist,CY_TaskSort,BT_TaskPrint,BT_TaskFreeze,BT_TaskActivate,CY_CpuUsage,tasktext2,BT_TaskUpdate,BT_TaskRemove,BT_TaskSignal,BT_TaskBreak,BT_TaskPriority,BT_TaskMore,BT_TaskExit,NULL);
  919.             DoMethod (CY_CpuUsage, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_CPUUSAGE);
  920.             DoMethod (CY_TaskSort, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_TASKSORT);
  921.             DoMethod (tasktext2,MUIM_Notify,MUIA_String_Acknowledge,MUIV_EveryTime,tasktext2,3,MUIM_CallHook,&cpuinterval_callhook,MUIV_TriggerValue);
  922.  
  923.             SetCloseRequest (WI_Tasks,ID_TASKEXIT);
  924.             SetListActive (tasklist,ID_TASKLV_ACTIVE);
  925.             SetListviewDoubleClick (tasklist,ID_TASKMORE);
  926.  
  927.             ShowTasks();
  928.  
  929.             SetWindowOpen (WI_Tasks,tasklist,ID_TASKEXIT);
  930.  
  931.             timer_ticking = FALSE;
  932.  
  933.             if (updatetimestate) CheckCPUUsage();
  934.          }
  935.       }
  936.    } else if ((! state) && (WI_Tasks)) {
  937.       if (patchsem) *switchstate = FALSE;
  938.  
  939.       if (cheattask) RemoveCheatTask();
  940.  
  941.       SetWindowClose (WI_Tasks,TRUE);
  942.  
  943.       FreeTasks();
  944.  
  945.       if (timer_ticking) {
  946.          AbortIO((struct IORequest *) TimerIORequest);
  947.          WaitIO((struct IORequest *) TimerIORequest);
  948.          timer_ticking = FALSE;
  949.       }
  950.  
  951.       DoMethod (AP_Scout,OM_REMMEMBER,WI_Tasks);
  952.       MUI_DisposeObject (WI_Tasks);
  953.  
  954.       WI_Tasks = NULL;
  955.       tasklist = NULL;
  956.    }
  957. }
  958.  
  959.